// 封装 axios
import axios from "axios";
import store from "@/store"; // 导入存储库
import { Toast } from "antd-mobile"; // 导入移动端提示框组件
import { customHistory } from "./history"; // 导入自定义历史记录
import { clearToken, getToken, setToken } from "@/utils/token"; // 导入令牌操作工具函数

// 创建 axios 实例
const http = axios.create({
  baseURL: "http://toutiao.itheima.net/v1_0", // 设置基础 URL
  timeout: 5000, // 设置超时时间
});

// 请求拦截器
http.interceptors.request.use((config) => {
  // 获取 token
  const {
    login: { token }, // 从存储库中获取登录令牌
  } = store.getState() as { login: { token: string } };

  // 除了登录请求外，其他请求统一添加 token
  if (!config.url?.startsWith("/authorizations")) {
    // 使用非空断言来去掉 headers 类型中的 undefined 类型
    config.headers!.Authorization = `Bearer ${token}`;
  }

  return config;
});

// 响应拦截器
http.interceptors.response.use(undefined, async (error) => {
  // 响应失败时，执行此处的回调函数
  if (!error.response) {
    // 网络超时
    Toast.show({
      content: "网络繁忙，请稍后再试",
      duration: 1000,
    });

    return Promise.reject(error);
  }

  if (error.response.status === 401) {
    try {
      let token = getToken();
      // 如果本地没有刷新令牌，给出提示并重定向到登录页
      if (!token.refresh_token) {
        localStorage.removeItem("HomeListItem");
        Toast.show({
          content: "登录超时，请重新登录",
          duration: 1000,
          afterClose() {
            customHistory.push("/login", {
              from: customHistory.location.pathname,
            });
          },
        });

        return new Promise(() => {});
      }
      // 刷新令牌存在并没有过期 则使用刷新令牌获取新的访问令牌
      const res = await http.put(
        `http://toutiao.itheima.net/v1_0/authorizations`,
        null,
        {
          headers: {
            Authorization: `Bearer ${token.refresh_token}`,
          },
        }
      );
      const tokens = {
        // 使用接口返回的最新 token
        token: res.data.data.token,
        // 接口没有返回新的 refresh_token，使用原来的
        refresh_token: token.refresh_token,
      };
      setToken(tokens); // 更新令牌
      store.dispatch({ type: "login/token", payload: tokens }); // 分发登录令牌到存储库

      // 继续完成原来要执行的操作
      // 比如，在获取个人资料时，token 超时了，最终，在拿到最新的 token 后
      // 要继续获取个人资料
      // 可以通过 error.config 来拿到原来发送的请求的相关信息
      // 所以，要执行原来的操作，只需要将 error.config 重新请求一次即可
      // 注意：此处，一定要返回 Promise 的结果
      return http(error.config);
    } catch (e) {
      // 如果换取新 token 的过程中，代码出错了，一般就说明 refresh_token 失效了
      // 此时，清空 token 并返回登录页面
      store.dispatch({ type: "login/logout" }); // 分发注销登录操作到存储库
      // 手动清理本地的 token
      clearToken();

      Toast.show({
        content: "登录超时，请重新登录",
        duration: 1000,
        afterClose: () => {
          customHistory.push("/login", {
            from: customHistory.location.pathname,
          });
        },
      });

      return new Promise(() => {});
    }
  }

  // return Promise.reject(error);
});

export { http }; // 导出封装后的 axios 实例
